package org.maven.dependencybrowser.gui;
/**********************************************************************
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:

**********************************************************************/
import org.maven.dependencybrowser.controller.ArtifactResolver;
import org.maven.dependencybrowser.controller.Controller;
import org.maven.dependencybrowser.controller.model.DuplicatesListManager;
import org.maven.dependencybrowser.implementations.WorkspaceLoader;
import org.maven.dependencybrowser.model.ArtifactInitialisationException;
import org.maven.repositorysnapshot.RepositorySnapshotFactory;

import javax.swing.*;
import javax.swing.table.JTableHeader;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class DependencyBrowserGui
{

    public static final String ROLE = "org.maven.dependencybrowser.gui.DependencyBrowserGui";

    private static final String PROPERTIES = "/META-INF/maven/org.maven/maven-dependency-browser-swing-gui/pom.properties";

    private JTree tree;
    private Controller controller;
    private JFrame frame;
    private JTable versions;
    private JTable duplicates;
    private WorkspaceLoader workspaceLoader;
    private ArtifactResolver resolver;
    private DuplicatesListManager duplicatesListManager;
    private ProgressMeter progressMeter;
    private RepositorySnapshotFactory repositorySnapshotFactory;

    public void open()
    {
        frame.setTitle("Maven Dependency Browser" + loadVersion());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

        topPanel.add(createLoadButton());
        topPanel.add(createCheckBox("compile", controller.getCheckShowCompile()));
        topPanel.add(createCheckBox("test", controller.getCheckShowTest()));
        topPanel.add(createCheckBox("runtime", controller.getCheckShowRuntime()));
        topPanel.add(createCheckBox("provided", controller.getCheckShowProvided()));
        topPanel.add(createCheckBox("exclusions", controller.getResolveExclusions()));
        topPanel.add(createSnapshotButton());

        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        JLabel progressLabel = new JLabel();
        bottomPanel.add(progressLabel);
        progressMeter = new ProgressMeter(progressLabel);
        progressMeter.ready();

        tree = new JTree(new DependencyTreeModel(workspaceLoader.getRoot()));
        tree.setCellRenderer(new DependencyTreeRenderer());
        versions = new JTable(new VersionsTableModel(duplicatesListManager));
        versions.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        versions.setDefaultRenderer(String.class, new SelectableTableModelRenderer());
        versions.addMouseListener(new MouseAdapter()
        {

            public void mouseClicked(MouseEvent e)
            {
                JTable table = (JTable) e.getComponent();
                duplicatesListManager.deselect();
                duplicatesListManager.getVersionsListManager().select(table.getSelectedRow());
                tree.repaint();
                versions.repaint();
                duplicates.repaint();
            }

        });
        versions.getTableHeader().addMouseListener(new MouseAdapter()
        {

            public void mouseClicked(MouseEvent e)
            {
                JTableHeader h = (JTableHeader) e.getSource();
                int vColIndex = h.getColumnModel().getColumnIndexAtX(e.getX());
                int mColIndex = h.getTable().convertColumnIndexToModel(vColIndex);
                duplicatesListManager.getVersionsListManager().setArtifactInstanceMapComparator(mColIndex);
                versions.repaint();
            }

        });
        duplicates = new JTable(new DuplicatesTableModel(duplicatesListManager));
        duplicates.setDefaultRenderer(String.class, new SelectableTableModelRenderer());
        duplicates.addMouseListener(new MouseAdapter()
        {

            public void mouseClicked(MouseEvent e)
            {
                JTable table = (JTable) e.getComponent();
                duplicatesListManager.select(table.getSelectedRow());
                tree.repaint();
                versions.repaint();
                duplicates.repaint();
            }

        });
        duplicates.getTableHeader().addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent e)
            {
                duplicatesListManager.setOrderByIdentifier();
                duplicates.repaint();
            }
        });

        JSplitPane versionsSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(versions), new JScrollPane(duplicates));
        JPanel versionsPanel = new JPanel();
        versionsPanel.setLayout(new BoxLayout(versionsPanel, BoxLayout.PAGE_AXIS));
        versionsPanel.add(versionsSplit);

        JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), versionsPanel);

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
        mainPanel.add(mainSplitPane);

        mainPanel.setPreferredSize(new Dimension(800, 600));

        frame.getContentPane().add(topPanel);
        frame.getContentPane().add(mainPanel);
        frame.getContentPane().add(bottomPanel);
        frame.pack();
        frame.setVisible(true);

        mainSplitPane.setDividerLocation(0.5);
        mainSplitPane.setResizeWeight(0.5);
        versionsSplit.setDividerLocation(0.7);
        versionsSplit.setResizeWeight(0.7);
    }

    private JButton createLoadButton()
    {
        JButton loadButton = new JButton("Load");
        loadButton.addActionListener(new ActionListener()
        {

            public void actionPerformed(ActionEvent e)
            {
                frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
                PomLoaderThread pomLoader = new PomLoaderThread(workspaceLoader, "pom loader")
                {

                    public void run()
                    {
                        try
                        {

                            duplicatesListManager.reset();
                            duplicates.repaint();
                            versions.repaint();

                            workspaceLoader.loadPom();
                            if (workspaceLoader.getRoot() != null)
                            {
                                workspaceLoader.getRoot().resolveDependencies(resolver, progressMeter);
                            }
                            progressMeter.ready();
                        }
                        catch (ArtifactInitialisationException e)
                        {
                            progressMeter.error(e);
                            e.printStackTrace();
                        }
                        catch (RuntimeException e)
                        {
                            progressMeter.error(e);
                            e.printStackTrace();
                        }
                        updateModel();
                    }
                };
                pomLoader.start();
            }

        });

        return loadButton;
    }

    private JCheckBox createCheckBox(String label, final Controller.BooleanController bcontroller)
    {
        JCheckBox checkBox = new JCheckBox(label, bcontroller.getValue());
        checkBox.addActionListener(new ActionListener()
        {

            public void actionPerformed(ActionEvent e)
            {
                frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
                bcontroller.toggle();
                PomLoaderThread pomLoader = new PomLoaderThread(workspaceLoader, "pom loader")
                {

                    public void run()
                    {
                        try
                        {
                            duplicatesListManager.reset();
                            workspaceLoader.reloadPom();
                            workspaceLoader.getRoot().resolveDependencies(resolver, progressMeter);
                            progressMeter.ready();
                        }
                        catch (ArtifactInitialisationException e)
                        {
                            progressMeter.error(e);
                        }
                        catch (RuntimeException e)
                        {
                            progressMeter.error(e);
                        }
                        updateModel();
                    }
                };
                pomLoader.start();
            }
        });
        return checkBox;
    }

    private abstract class PomLoaderThread implements Runnable
    {

        protected WorkspaceLoader workspaceLoader;
        private String name;

        public PomLoaderThread(WorkspaceLoader workspaceLoader, String name)
        {
            this.workspaceLoader = workspaceLoader;
            this.name = name;
        }

        public void start()
        {
            Thread thread = new Thread(this);
            thread.setName(name);
            thread.setDaemon(true);
            thread.start();
        }
    }

    /**
     * called by background thread to queue a gui model reload
     */
    public void updateModel()
    {
        Runnable modelUpdate = new Runnable()
        {

            public void run()
            {
                tree.setModel(new DependencyTreeModel(workspaceLoader.getRoot()));
                versions.setModel(new VersionsTableModel(duplicatesListManager));
                duplicates.setModel(new DuplicatesTableModel(duplicatesListManager));
                frame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        };
        SwingUtilities.invokeLater(modelUpdate);
    }

    /**
     * extract the version number from the maven pom.properties file. fail
     * silently if we can't find it as this functionality is optional.
     */
    private String loadVersion()
    {
        InputStream resourceStream = DependencyBrowserGui.class.getResourceAsStream(PROPERTIES);
        if (resourceStream == null)
        {
            return "";
        }
        Properties properties = new Properties();
        try
        {
            properties.load(resourceStream);
        }
        catch (IOException e)
        {
            return "";
        }
        String version = properties.getProperty("version");
        if (version == null || version.trim().length() == 0)
        {
            return "";
        }
        return " " + version;
    }

    private JButton createSnapshotButton()
    {
        JButton snapshotButton = new JButton("Snapshot");
        snapshotButton.setEnabled(repositorySnapshotFactory.isSnapshotEnabled());
        snapshotButton.addActionListener(new ActionListener()
        {

            public void actionPerformed(ActionEvent e)
            {
                repositorySnapshotFactory.createSnapshot(progressMeter);
            }
        });
        return snapshotButton;
    }

}
